import set from 'lodash/set';
import { gqcPermissionCheck } from '@kuiper/auth';

import errorCodesBuilder from '../helpers/errorCodesBuilder';
import dealWithBalanceGQCMiddleware from '../plugins/billing/dealWithBalanceGQCMiddleware';
import removeManyResolveBuilder from './removeManyResolveBuilder';
import findByIdsEmpty from './Job/findByIdsEmpty';

const errorCodes = errorCodesBuilder();

export default server => {
	const {
		app: {
			schemaComposer,
			model: { AlertGroup },
		},
	} = server;

	const tc = server.methods.registerGraphQLSchema({
		name: 'AlertGroup',
		model: AlertGroup,
		queryFields: {
			Many: 'findMany',
			Count: 'count',
			One: 'findOne',
			Pagination: 'pagination',
		},
		mutationFields: {
			CreateOne: 'createOne',
			UpdateOne: 'updateOne',
		},
		onPreAddFields(tc) {
			const {
				app: {
					graphqlResolvers,
					schema: { AlertReceiver },
				},
			} = server;

			tc.addRelation('receivers', {
				resolver: () =>
					AlertReceiver.mongooseResolvers
						.dataLoaderMany({ lean: true })
						.wrapResolve(findByIdsEmpty),
				prepareArgs: {
					_ids: source => source.receiverIds.filter(Boolean),
				},
				projection: { receiverIds: 1 },
			});

			graphqlResolvers.Query.AlertGroupCount = graphqlResolvers.Query.AlertGroupCount.withMiddlewares(
				[
					gqcPermissionCheck({
						required: 'cloud-monitor\x01listAlertGroup',
						selfOnlyArgsBuilder(
							_source,
							args,
							{
								request: {
									auth: {
										credentials: { uid },
									},
								},
							}
						) {
							set(args, ['filter', 'uid'], uid);
						},
					}),
				]
			);

			graphqlResolvers.Query.AlertGroupMany = graphqlResolvers.Query.AlertGroupMany.withMiddlewares(
				[
					gqcPermissionCheck({
						required: 'cloud-monitor\x01listAlertGroup',
						selfOnlyArgsBuilder(
							_source,
							args,
							{
								request: {
									auth: {
										credentials: { uid },
									},
								},
							}
						) {
							set(args, ['filter', 'uid'], uid);
						},
					}),
				]
			);

			graphqlResolvers.Query.AlertGroupOne = graphqlResolvers.Query.AlertGroupOne.withMiddlewares(
				[
					gqcPermissionCheck({
						required: 'cloud-monitor\x01listAlertGroup',
						selfOnlyArgsBuilder(
							_source,
							args,
							{
								request: {
									auth: {
										credentials: { uid },
									},
								},
							}
						) {
							set(args, ['filter', 'uid'], uid);
						},
					}),
				]
			);

			graphqlResolvers.Query.AlertGroupPagination = graphqlResolvers.Query.AlertGroupPagination.withMiddlewares(
				[
					gqcPermissionCheck({
						required: 'cloud-monitor\x01listAlertGroup',
						selfOnlyArgsBuilder(
							_source,
							args,
							{
								request: {
									auth: {
										credentials: { uid },
									},
								},
							}
						) {
							set(args, ['filter', 'uid'], uid);
						},
					}),
				]
			);

			graphqlResolvers.Mutation.AlertGroupCreateOne = graphqlResolvers.Mutation.AlertGroupCreateOne.withMiddlewares(
				[
					gqcPermissionCheck({
						required: 'cloud-monitor\x01createAlertGroup',
						selfOnlyArgsBuilder(
							_source,
							args,
							{
								request: {
									auth: {
										credentials: { uid, permissions },
									},
								},
							}
						) {
							set(args, ['record', 'uid'], uid);
						},
					}),
					dealWithBalanceGQCMiddleware((_, args, context) => ({
						server: context.request.server,
						uid: args.record.uid,
						ops: [
							{
								key: 'alertGroup',
								value: -1,
							},
						],
					})),
					async (resolve, source, args, context, info) => {
						const {
							request: {
								log,
								server: {
									app: {
										model: { AlertGroup, AlertReceiver },
									},
								},
							},
						} = context;

						let ret;
						try {
							const exists = await AlertGroup.findOne({
								uid: args.filter.uid,
								name: args.record.name,
							});
							if (exists) {
								throw errorCodes['[0A][添加告警组]已添加该名称告警组'];
							}
							const receivers = await AlertReceiver.find({
								_id: { $in: args.record.receiverIds },
							});
							ret = await resolve(source, args, context, info);
							log.audit(
								{
									module: 'alertReceiver',
									activeType: 'create',
									actionMessage: '更新告警组',
									detail: `在告警设置中新增告警组名${
										args.record.name
									}，告警人${receivers.map(x => x.name).join('、')}`,
								},
								'新建告警组'
							);
						} catch (err) {
							const error = errorCodes[
								'[0A][添加告警组]保存Mongo记录失败'
							].from(err);
							context.request.log.error(
								{ error, record: args.record },
								error.rawMessage
							);
							throw error;
						}

						return ret;
					},
				]
			);

			graphqlResolvers.Mutation.AlertGroupUpdateOne = graphqlResolvers.Mutation.AlertGroupUpdateOne.withMiddlewares(
				[
					gqcPermissionCheck({
						required: 'cloud-monitor\x01editAlertGroup',
						selfOnlyArgsBuilder(
							_source,
							args,
							{
								request: {
									auth: {
										credentials: { uid },
									},
								},
							}
						) {
							set(args, ['filter', 'uid'], uid);
						},
					}),
					async (resolve, source, args, context, info) => {
						const {
							request: {
								log,
								server: {
									app: {
										model: { AlertGroup, AlertReceiver },
									},
								},
							},
						} = context;

						if (args.record.name) {
							try {
								const dup = await AlertGroup.findOne({
									uid: args.filter.uid,
									_id: { $ne: args.filter._id },
									name: args.record.name,
								});
								if (dup) {
									throw errorCodes['[0A][编辑告警组]和已有告警组重名'];
								}
							} catch (err) {
								const error = errorCodes[
									'[0A][编辑告警人]查找重名Mongo记录失败'
								].from(err);
								log.error({ error, record: args.record }, error.rawMessage);
								throw error;
							}
						}

						const receivers = await AlertReceiver.find({
							_id: { $in: args.record.receiverIds },
						});
						log.audit(
							{
								module: 'alertReceiver',
								activeType: 'create',
								actionMessage: '更新告警组',
								detail: `告警设置中更新告警组，组名：${
									args.record.name
								}，告警人：${receivers.map(x => x.name).join('、')}。`,
							},
							'更新告警组'
						);
						return resolve(source, args, context, info);
					},
				]
			);
		},
	});

	tc.mongooseResolvers.removeMany();
	schemaComposer.Mutation.addFields({
		AlertGroupRemoveMany: {
			description: '删除告警组',
			type: 'RemoveManyAlertGroupPayload',
			args: {
				filter: schemaComposer.createInputTC({
					name: 'AlertGroupRemoveManyFilterCustomInput',
					fields: {
						_ids: '[MongoID]',
					},
				}),
			},
			resolve: removeManyResolveBuilder({
				model: AlertGroup,
				permissionRequired: 'cloud-monitor\x01removeAlertGroup',
				balanceOps: [
					{
						key: 'alertGroup',
						value: 1,
					},
				],
				prepareFilter: ({
					args: {
						filter: { _ids },
					},
				}) => ({ _id: { $in: _ids } }),
				module: 'group',
			}),
		},
	});
};
